package com.glink.gateway.service.authorize.impl;

import com.glink.gateway.config.WhiteListConfig;
import com.glink.gateway.service.authorize.WhiteListService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.regex.Pattern;

/**
 * @author rhl
 * @date 2022/6/8 17:53
 * @since  1.0
 */
@Service
public class WhiteListServiceImpl implements WhiteListService {

    @Autowired
    WhiteListConfig whiteListConfig;

    @Override
    public boolean match(String path) {
        List<String> whiteList = whiteListConfig.getWhiteList();
        for (String s : whiteList) {
            if (wildcardEquals(s, path)) {
                return true;
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 白名单跨系统的匹配
     *
     * @param path 路径
     * @return 匹配结果
     */
    @Override
    public boolean crossSystemMatch(String path) {
        List<String> whiteList = whiteListConfig.getCrossSystemWhiteList();
        for (String s : whiteList) {
            if (wildcardEquals(s, path)) {
                return true;
            }
        }
        return Boolean.FALSE;
    }

    /**
     * 通配符模式
     *
     * @param whitePath - 白名单地址
     * @param reqPath   - 请求地址
     * @return
     */
    private static boolean wildcardEquals(String whitePath, String reqPath) {
        String regPath = getRegPath(whitePath);
        return Pattern.compile(regPath).matcher(reqPath).matches();
    }

    /**
     * 将通配符表达式转化为正则表达式
     *
     * @param path
     * @return
     */
    private static String getRegPath(String path) {
        char[] chars = path.toCharArray();
        int len = chars.length;
        StringBuilder sb = new StringBuilder();
        boolean preX = false;
        for (int i = 0; i < len; i++) {
            //遇到*字符
            if (chars[i] == '*') {
                //如果是第二次遇到*，则将**替换成.*
                if (preX) {
                    sb.append(".*");
                    preX = false;
                    //如果是遇到单星，且单星是最后一个字符，则直接将*转成[^/]*
                } else if (i + 1 == len) {
                    sb.append("[^/]*");
                    //否则单星后面还有字符，则不做任何动作，下一把再做动作
                } else {
                    preX = true;
                    continue;
                }
                //遇到非*字符
            } else {
                //如果上一把是*，则先把上一把的*对应的[^/]*添进来
                if (preX) {
                    sb.append("[^/]*");
                    preX = false;
                }
                //接着判断当前字符是不是?，是的话替换成.
                if (chars[i] == '?') {
                    sb.append('.');
                    //不是?的话，则就是普通字符，直接添进来
                } else {
                    sb.append(chars[i]);
                }
            }
        }
        return sb.toString();
    }
}
